/*
 * 
 */

#include <stdlib.h>
#include <string.h>
#include <freeradius-devel/base64.h>


static const char* enc64table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

char *base64_encode(char *clear, size_t len, size_t *b64_len) {
                                                               
        char *code = NULL;                                     
        char *p;          
                          
        code = malloc(4*((len+2)/3) + 1);
                                         
        if (code == NULL) {              
                return NULL;
        }                   
                            
        p = code;
                 
        *b64_len = 0;
                     
        while (len-- >0)
        {               
                register int x, y;
                                  
                x = *clear++;     
                *p++ = enc64table[(x >> 2) & 63];
                *b64_len += 1;                   
                if (len-- <= 0) {                
                        *p++ = enc64table[(x << 4) & 63];
                        *p++ = '=';                      
                        *p++ = '=';                      
                        *b64_len += 3;
                        break;        
                }                     
                              
                y = *clear++;
                *p++ = enc64table[((x << 4) | ((y >> 4) & 15)) & 63];
                *b64_len += 1;
                if (len-- <= 0)
                {
                        *p++ = enc64table[(y << 2) & 63];
                        *p++ = '=';
                        *b64_len += 2;
                        break;
                }
        
                x = *clear++;
                *p++ = enc64table[((y << 2) | ((x >> 6) & 3)) & 63];
                *p++ = enc64table[x & 63];
                *b64_len += 2;
        }
        *p = 0;
        return code;
}       


/* 
 *  base 64 decode is taken from exim v3 
 *  
 */

static unsigned char dec64table[] = {
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*  0-15 */
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 16-31 */
  255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, /* 32-47 */
   52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, /* 48-63 */
  255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, /* 64-79 */
   15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, /* 80-95 */
  255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96-111 */
   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255  /* 112-127*/
};

void* base64_decode(char *code, size_t *size) {
  register int x, y;
  *size = 3*((int)strlen(code)/4);
  char *ptr = NULL;
  char *result = NULL;

  result = ptr = malloc(*size + 1);

  while ((x = (unsigned char)(*code++)) != 0) {
    if (x > 127 || (x = dec64table[x]) == 255) {
      *size = 0;
      return NULL;
    }

    if ((y = (unsigned char)(*code++)) == 0 || (y = dec64table[y]) == 255) {
      *size = 0;
      return NULL;
    }
    *ptr++ = (x << 2) | (y >> 4);

    if ((x = (unsigned char)(*code++)) == '=') {

      if (*code++ != '=' || *code != 0) {
        *size = 0;
        return NULL;
      }

    } else {

      if (x > 127 || (x = dec64table[x]) == 255) {
        *size = 0;
        return NULL;
      }
      *ptr++ = (y << 4) | (x >> 2);
      if ((y = (unsigned char)(*code++)) == '=') {
        if (*code != 0) {
          *size = 0;
          return NULL;
        }
      } else {
        if (y > 127 || (y = dec64table[y]) == 255)  {
          *size = 0;
          return NULL;
        }
        *ptr++ = (x << 6) | y;
      }
    }
  }
  *ptr = 0;

  return result;
}
